﻿using System;
using System.Collections.Generic;
using System.Linq;
using Acme.Common.Utility;
using Acme.Entities;

namespace Acme.Business
{

    /// <summary>
    /// This repository simulates a data store by only working with deep copies of events.  
    /// By only using deep copies, the UI never gets the same instance of an Event that is stored in the repository.
    /// </summary>
    public class EventRepository : IEventRepository
    {

        #region Declarations

        readonly List<Event> _events;
        const Int32 INT32_SUCCESS = 1;
        const Int32 INT32_NOTFOUND = 0;
        const String STRING_ENTITY = "entity";

        #endregion //Declarations

        #region Constructor

        public EventRepository()
        {
            _events = new List<Event>();

            Event @event = this.Create();

            @event.EventDate = new DateTime(2009, 12, 25);
            @event.Location = "Home";
            @event.Notes = "Grandma and Grandpa will be coming at 4:00pm";
            @event.Title = "Christmas 2009 at home";

            @event.Expenses.Add(new Expense() { Recipient = "Matthew", Description = "XBOX 360", Cost = 399.99m });
            @event.Expenses.Add(new Expense() { Recipient = "Matthew", Description = "Halo 3", Cost = 26.48m });

            this.Save(@event);

            @event = this.Create();

            @event.EventDate = new DateTime(2010, 7, 4);
            @event.Location = "Washington, DC";
            @event.Notes = "Everyone meet at the Washington Monument at 8:00pm";
            @event.Title = "4th of July Family Celebration";

            @event.Expenses.Add(new Expense() { Recipient = "Family", Description = "Airfare", Cost = 2000.00m });
            @event.Expenses.Add(new Expense() { Recipient = "Family", Description = "Hotel", Cost = 900.00m });
            @event.Expenses.Add(new Expense() { Recipient = "Family", Description = "Food", Cost = 550.00m });

            this.Save(@event);

        }

        #endregion //Constructor

        #region Methods

        /// <summary>
        /// Returns all Events as an EventSearchResult
        /// </summary>
        public IEnumerable<EventSearchResult> GetSearchResults()
        {
            var query = from e in _events orderby e.EventDate select new EventSearchResult(e.Id, e.Title, e.EventDate);
            return query.ToList();
        }

        /// <summary>
        /// Gets a Deep Copy of the event by id.
        /// </summary>
        /// <param name="id">The id.</param>
        public Event GetById(Guid id)
        {
            var @event = _events.Where(e => e.Id.Equals(id)).SingleOrDefault();
            return @event == null ? null : DeepCopy.Make(@event);
        }

        Event GetLocalCopyById(Guid id)
        {
            return _events.Where(e => e.Id.Equals(id)).SingleOrDefault();
        }

        /// <summary>
        /// Gets the count of Events.
        /// </summary>
        public Int32 GetCount()
        {
            return _events.Count;
        }

        /// <summary>
        /// Removes the specified @event.
        /// </summary>
        /// <param name="event">The event.</param>
        public Int32 Remove(Event @event)
        {
            if (@event == null)
            {
                throw new ArgumentNullException(STRING_ENTITY);
            }

            var localEvent = this.GetLocalCopyById(@event.Id);

            if (localEvent != null && _events.Remove(localEvent))
            {
                return INT32_SUCCESS;
            }
            return INT32_NOTFOUND;
        }

        /// <summary>
        /// Saves the specified @event.
        /// </summary>
        /// <param name="event">The event.</param>
        public Int32 Save(Event @event)
        {
            if (@event == null)
            {
                throw new ArgumentNullException(STRING_ENTITY);
            }

            var localEvent = this.GetLocalCopyById(@event.Id);

            if (localEvent != null)
            {
                this.Remove(localEvent);
            }

            _events.Add(@event);

            return INT32_SUCCESS;
        }

        /// <summary>
        /// Creates and returns an Event.  This simulates the business layer creating and preparing the entity Object for use in the program.
        /// </summary>
        public Event Create()
        {
            return new Event();
        }

        #endregion //Methods
    }
}
